package com.yesep.learn.netty.protocol.session;

import java.util.List;

import com.yesep.learn.netty.protocol.common.Constants;
import com.yesep.learn.netty.protocol.exception.CommandException;
import com.yesep.learn.netty.protocol.exception.CommandParseException;
import com.yesep.learn.netty.protocol.exception.CommandPnumException;
import com.yesep.learn.netty.protocol.util.CommandUtil;

import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import lombok.Data;

/**
 * @Description:
 */
@Data
public class Command {

	/**
	 * 请求编码
	 * 精确到毫秒的时间戳:QN=YYYYMMDDhhmmsszzz，用来唯一标识一次命令交互 
	 */
	private String QN;

	/**
	 * 系统编码
	 */
	private String ST;

	/**
	 * 系统编码
	 */
	private String CN;

	/**
	 * 访问密码
	 */
	private String PW;

	/**
	 * 设备唯一标识
	 * 这个标识固化在设备中，用于唯一标识一个设备。由 EPC-96 编码转化的字符串组成，即由 24 个 0~9，A~F 的字符组成。
	 */
	private String MN;

	/**
	 * 拆分包及应答标志 
	 * Flag=标志位，这个标志位包含标准版本号、是否拆分包、数据是否应答。 V5 V4 V3 V2 V1 V0 D A
	 * V5~V0：标准版本号；Bit：000000 表示标准 HJ/T 212-2005，000001 表 示本次标准修订版本号。
	 * A：命令是否应答；Bit：1-应答，0-不应答。 
	 * D：是否有数据包序号；Bit：1-数据包中包含包号和总包数两部分,0-数据包中不包含包号和总包数两部分。
	 * 示例：Flag=7 表示标准版本为本次修订版本号，数据段需要拆分并且命 令需要应答
	 */
	private Integer Flag;

	/**
	 * 指示本次通讯中总共包含的包数 
	 * 注：不分包时可以没有本字段，与标志位有关 
	 */
	private Integer PNUM;

	/**
	 * 指令参数
	 * CP=&&数据区&&
	 */
	private Integer PNO;

	private CPData CP = new CPData();

	public Command() {
	}

	public Command(String ST, String CN, String PW, String MN, Integer Flag) {
		this.ST = ST;
		this.CN = CN;
		this.PW = PW;
		this.MN = MN;
		this.Flag = Flag;
	}

	public Command(String QN, String ST, String CN, String PW, String MN, Integer Flag) {
		this(ST, CN, PW, MN, Flag);
		this.QN = QN;
	}

	/**
	 * @param text 接收的议事消息报文
	 */
	public Command(String data) throws CommandParseException {
		List<String> rs = ReUtil.getAllGroups(CommandUtil.CMD_PATTERN, data, false);
		if (rs.size() != 11) {
			throw new CommandParseException();
		}
		this.setQN(rs.get(0));
		this.setST(rs.get(1));
		this.setCN(rs.get(2));
		this.setPW(rs.get(3));
		this.setMN(rs.get(4));
		this.setFlag(Integer.valueOf(rs.get(5)));
		if (null != rs.get(7)) {
			this.setPNUM(Integer.valueOf(rs.get(7)));
		}
		if (null != rs.get(9)) {
			this.setPNO(Integer.valueOf(rs.get(9)));
		}

		String cpString = rs.get(10);
		for (String ss : cpString.split(Constants.DATA_SPLIT)) {
			for (String s : ss.split(Constants.DATA_SPLIT_SAME)) {
				String[] dd = s.split(Constants.DATA_EQ);
				if (dd[0].indexOf(Constants.DATA_SPLIT_INTERVAL) < 0) {//普通参数
					CP.addParam(dd[0], dd[1]);
				} else {//监控指标数据
					String[] d = dd[0].split(Constants.DATA_SPLIT_INTERVAL);
					CP.addData(d[0], d[1], dd[1]);
				}
			}
		}
	}

	/**
	 *     添加子包
	 * @param msg
	 */
	public void addSubPkg(String msg) throws CommandParseException {
	}

	/**
	 * @return 是否有数据包序号
	 */
	public boolean isSubPkg() throws CommandParseException {
		String s = getFlagBinaryString();
		String v = s.substring(6, 7);
		return "1".equals(v) && null != this.getPNUM() && null != this.getPNO();//1—数据包中包含包号和总包数两部分，0—数据包中不包含包号和总包数两部分。
	}

	/**
	 * 获取协议版本号
	 * 
	 * @return 版本号
	 */
	public String getVersion() throws CommandParseException {
		String s = getFlagBinaryString();
		String v = s.substring(6);
		return v;
	}

	private String getFlagBinaryString() throws CommandParseException {
		if (null == Flag)
			throw new CommandParseException("Flag is null");
		String s = StrUtil.padPre(Integer.toBinaryString(Flag), 8, "0");
		return s;
	}

	public void addCPParam(String key, String value) {
		getCP().addParam(key, value);
	}

	public void addCPData(String polId, String type, String value) {
		getCP().addData(polId, type, value);
	}

	/**
	 * @return 命令是否需要应答
	 */
	public boolean needResp() throws CommandParseException {
		String s = getFlagBinaryString();
		String v = s.substring(7);
		return "1".equals(v);//1-应答，0-不应答。
	}

	/**
	 * 返回应答命令 
	 * @return
	 */
	public String getResponse() {
		return "";
	}

	@Override
	public String toString() {
		StringBuffer data = new StringBuffer();
		if (null == this.QN) {
			this.QN = CommandUtil.getQN();
		}
		data.append("QN=").append(this.QN).append(";");
		data.append("ST=").append(this.ST).append(";");
		data.append("CN=").append(this.CN).append(";");
		data.append("PW=").append(this.PW).append(";");
		data.append("MN=").append(this.MN).append(";");
		data.append("Flag=").append(this.Flag).append(";");
		if (null != this.PNUM) {
			data.append("PNUM=").append(this.PNUM).append(";");
		}
		if (null != this.PNO) {
			data.append("PNO=").append(this.PNO).append(";");
		}
		data.append("CP=&&").append(this.CP).append("&&");
		StringBuffer sb = new StringBuffer();
		sb.append(Constants.PKG_HEADER);//包头
		sb.append(StrUtil.padPre(String.valueOf(data.length()), 4, "0"));//数据区长度
		sb.append(data);//数据区
		sb.append(CommandUtil.CRC16(data.toString()));//CRC
		sb.append(Constants.PKG_FOOTER);//包尾
		return sb.toString();
	}
}
